home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 242 / Issue 242 - April 2008 - DPCS0408DVD.ISO / Open Source / AutoHotKey / Source / AutoHotkey104705_source.exe / source / hook.h < prev    next >
Encoding:
C/C++ Source or Header  |  2007-01-01  |  16.3 KB  |  273 lines

  1. /*
  2. AutoHotkey
  3.  
  4. Copyright 2003-2007 Chris Mallett (support@autohotkey.com)
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15. */
  16.  
  17. #ifndef hook_h
  18. #define hook_h
  19.  
  20. #include "stdafx.h" // pre-compiled headers
  21. #include "hotkey.h" // Use here and also by hook.cpp for ChangeHookState(), which reads from static Hotkey class vars.
  22.  
  23. // WM_USER is the lowest number that can be a user-defined message.  Anything above that is also valid.
  24. // NOTE: Any msg about WM_USER will be kept buffered (unreplied-to) whenever the script is uninterruptible.
  25. // If this is a problem, try making the msg have an ID less than WM_USER via a technique such as that used
  26. // for AHK_USER_MENU (perhaps WM_COMMNOTIFY can be "overloaded" to contain more than one type of msg).
  27. // Also, it has been announced in OnMessage() that message numbers between WM_USER and 0x1000 are earmarked
  28. // for possible future use by the program, so don't use a message above 0x1000 without good reason.
  29. enum UserMessages {AHK_HOOK_HOTKEY = WM_USER, AHK_HOTSTRING, AHK_USER_MENU, AHK_DIALOG, AHK_NOTIFYICON
  30.     , AHK_RETURN_PID, AHK_EXIT_BY_RELOAD, AHK_EXIT_BY_SINGLEINSTANCE
  31.     // Allow some room here in between for more "exit" type msgs to be added in the future (see below comment).
  32.     , AHK_GUI_ACTION = WM_USER+20 // Avoid WM_USER+100/101 and vicinity.  See below comment.
  33.     // v1.0.43.05: On second thought, it seems better to stay close to WM_USER because the OnMessage page
  34.     // documents, "it is best to choose a number greater than 4096 (0x1000) to the extent you have a choice.
  35.     // This reduces the chance of interfering with messages used internally by current and future versions..."
  36.     // v1.0.43.03: Changed above msg number because Micha reports that previous number (WM_USER+100) conflicts
  37.     // with msgs sent by HTML control (AHK_CLIPBOARD_CHANGE) and possibly others (I think WM_USER+100 may be the
  38.     // start of a range used by other common controls too).  So trying a higher number that's (hopefully) very
  39.     // unlikely to be used by OS features.
  40.     , AHK_CLIPBOARD_CHANGE, AHK_HOOK_TEST_MSG, AHK_CHANGE_HOOK_STATE, AHK_GETWINDOWTEXT};
  41. // NOTE: TRY NEVER TO CHANGE the specific numbers of the above messages, since some users might be
  42. // using the Post/SendMessage commands to automate AutoHotkey itself.  Here is the original order
  43. // that should be maintained:
  44. // AHK_HOOK_HOTKEY = WM_USER, AHK_HOTSTRING, AHK_USER_MENU, AHK_DIALOG, AHK_NOTIFYICON, AHK_RETURN_PID
  45.  
  46. // UPDATE to the below comment: After a careful review, it seems best to buffer a user's selection of
  47. // a custom menu item if the current quasi-thread is uninterruptible.  This is exactly the same way
  48. // hotkeys are buffered.  By making a thread truly uninterruptible, behavior is more consistent with
  49. // what most users would want, though it should be noted that this also makes it impossible for the
  50. // OnExit subroutine to be interrupted by a custom menu item, even one that is designed to simply
  51. // exit the script (by means of aborting the on-exit subroutine).  Another reason to buffer the
  52. // selection of a custom menu item is that we don't want to interrupt the current thread if is
  53. // right in the middle of executing a single line, e.g. doing something with the deref buffer
  54. // (during which time an interruption might destroy the buffer's contents) or trying to open the
  55. // clipboard or save data to it.  This particular weakness may be resolved when/if a dedicated
  56. // thread is created to maintain the hook(s), thus allowing critical operations such as opening
  57. // the clipboard to use a true Sleep() rather than MsgSleep().
  58. // Since WM_COMMNOTIFY is never generated by the Win32 API, and since we want AHK_USER_MENU to be
  59. // an ID less than WM_HOTKEY so that it doesn't get filtered out when the script is uninterruptible,
  60. // the following trick is used to map our user-defined messages onto WM_COMMNOTIFY by sacrificing the
  61. // wParam part of the message (using it as an indicator of what the message really is).
  62. // Another reserved msg that might be fairly safe is WM_MDIICONARRANGE, but it's far less preferable:
  63. #define TRANSLATE_AHK_MSG(msg, wparam) \
  64.     if (msg == WM_COMMNOTIFY)\
  65.     {\
  66.         msg = (UINT)wparam;\
  67.         wparam = 0;\
  68.     } // In the above, wparam is made zero to help catch bugs.
  69.  
  70. // And these macros are kept here so that all this trickery is centrally located and thus more maintainable:
  71. #define ASK_INSTANCE_TO_CLOSE(hwnd, reason) PostMessage(hwnd, WM_COMMNOTIFY, reason, 0);
  72.  
  73. // POST_AHK_USER_MENU: A gui_index value >= 0 is passed with the message if it came from a GUI's menu bar.
  74. // This is done because it's good way to pass the info, but also so that its value will be in sync with the
  75. // timestamp of the message (in case the message is stuck in the queue for a long time).  No pointer is
  76. // passed in this case since they might become invalid between the time the msg is posted vs. processed.
  77. #define POST_AHK_USER_MENU(hwnd, menu, gui_index) PostMessage(hwnd, AHK_USER_MENU, gui_index, menu);
  78. #define POST_AHK_GUI_ACTION(hwnd, control_index, gui_event, event_info) PostMessage(hwnd, AHK_GUI_ACTION \
  79.     , (WPARAM)(((control_index) << 16) | (gui_event)), (LPARAM)(event_info)); // Caller must ensure that gui_event is less than 0xFFFF.
  80. // POST_AHK_DIALOG:
  81. // Post a special msg that will attempt to force it to the foreground after it has been displayed,
  82. // since the dialog often will flash in the task bar instead of becoming foreground.
  83. // It's enough just to queue up a single message that dialog's message pump will forward to our
  84. // main window proc once the dialog window has been displayed.  This avoids the overhead of creating
  85. // and destroying the timer (although the timer may be needed anyway if any timed subroutines are
  86. // enabled).  My only concern about this is that on some OS's, or on slower CPUs, the message may be
  87. // received too soon (before the dialog window actually exists) resulting in our window proc not
  88. // being able to ensure that it's the foreground window.  That seems unlikely, however, since
  89. // MessageBox() and the other dialog invocating API calls (for FileSelectFile/Folder) likely
  90. // ensures its window really exists before dispatching messages.
  91. #define POST_AHK_DIALOG(timeout) PostMessage(g_hWnd, WM_COMMNOTIFY, AHK_DIALOG, (LPARAM)timeout);
  92.  
  93. // Some reasoning behind the below data structures: Could build a new array for [sc][sc] and [vk][vk]
  94. // (since only two keys are allowed in a ModifierVK/SC combination, only 2 dimensions are needed).
  95. // But this would be a 512x512 array of shorts just for the SC part, which is 512K.  Instead, what we
  96. // do is check whenever a key comes in: if it's a suffix and if a non-standard modifier key of any kind
  97. // is currently down: consider action.  Most of the time, an action be found because the user isn't
  98. // likely to be holding down a ModifierVK/SC, while pressing another key, unless it's modifying that key.
  99. // Nor is he likely to have more than one ModifierVK/SC held down at a time.  It's still somewhat
  100. // inefficient because have to look up the right prefix in a loop.  But most suffixes probably won't
  101. // have more than one ModifierVK/SC anyway, so the lookup will usually find a match on the first
  102. // iteration.
  103. struct vk_hotkey
  104. {
  105.     vk_type vk;
  106.     HotkeyIDType id_with_flags;
  107. };
  108. struct sc_hotkey
  109. {
  110.     sc_type sc;
  111.     HotkeyIDType id_with_flags;
  112. };
  113.  
  114. // Style reminder: Any POD structs (those without any methods) don't use the "m" prefix
  115. // for member variables because there's no need: the variables are always prefixed by
  116. // the struct that owns them, so there's never any ambiguity:
  117. struct key_type
  118. {
  119.     ToggleValueType *pForceToggle;  // Pointer to a global variable for toggleable keys only.  NULL for others.
  120.     modLR_type as_modifiersLR; // If this key is a modifier, this will have the corresponding bit(s) for that key.
  121.     HotkeyIDType hotkey_to_fire_upon_release; // A up-event hotkey queued by a prior down-event.
  122.     // Keep sub-32-bit members contiguous to save memory without having to sacrifice performance of
  123.     // 32-bit alignment:
  124.     #define PREFIX_ACTUAL 1 // Values for used_as_prefix below, for places that need to distinguish between type of prefix.
  125.     #define PREFIX_FORCED 2 // v1.0.44: Added so that a neutral hotkey like Control can be forced to fire on key-up even though it isn't actually a prefix key.
  126.     UCHAR used_as_prefix; // Whether a given virtual key or scan code is even used by a hotkey.
  127.     bool used_as_suffix;  //
  128.     bool used_as_key_up;  // Whether this suffix also has an enabled key-up hotkey.
  129.     UCHAR no_suppress; // Contains bitwise flags such as NO_SUPPRESS_PREFIX.
  130.     bool is_down; // this key is currently down.
  131.     bool it_put_alt_down;  // this key resulted in ALT being pushed down (due to alt-tab).
  132.     bool it_put_shift_down;  // this key resulted in SHIFT being pushed down (due to shift-alt-tab).
  133.     bool down_performed_action; // the last key-down resulted in an action (modifiers matched those of a valid hotkey)
  134.     bool hotkey_down_was_suppressed; // Whether the down-event for a key was suppressed (thus its up-event should be too).
  135.     // The values for "was_just_used" (zero is the inialized default, meaning it wasn't just used):
  136.     char was_just_used; // a non-modifier key of any kind was pressed while this prefix key was down.
  137.     // And these are the values for the above (besides 0):
  138.     #define AS_PREFIX 1
  139.     #define AS_PREFIX_FOR_HOTKEY 2
  140.     bool sc_takes_precedence; // used only by the scan code array: this scan code should take precedence over vk.
  141.     UCHAR nModifierVK;
  142.     UCHAR nModifierSC;
  143.     // User is likely to use more modifying vks than we do sc's, since sc's are rare:
  144.     #define MAX_MODIFIER_VKS_PER_SUFFIX 50
  145.     #define MAX_MODIFIER_SCS_PER_SUFFIX 16
  146.     vk_hotkey ModifierVK[MAX_MODIFIER_VKS_PER_SUFFIX];
  147.     sc_hotkey ModifierSC[MAX_MODIFIER_SCS_PER_SUFFIX];
  148. }; // Keep the macro below in sync with the above.
  149.  
  150. // Fix for v1.0.43.01: Caller wants item.no_suppress initialized to remove all flags except NO_SUPPRESS_STATES.
  151. // Otherwise, a hotkey that removes the mouse hook will cause a non-suppressed key-up to become suppressed,
  152. // causing the key to get stuck down.  The following two-line script can reproduce this:
  153. //   ~LCtrl::Hotkey, RButton, Off
  154. //   RButton::return
  155. #define RESET_KEYTYPE_ATTRIB(item) \
  156. {\
  157.     item.nModifierVK = 0;\
  158.     item.nModifierSC = 0;\
  159.     item.used_as_prefix = 0;\
  160.     item.used_as_suffix = false;\
  161.     item.used_as_key_up = false;\
  162.     item.no_suppress &= NO_SUPPRESS_STATES;\
  163.     item.sc_takes_precedence = false;\
  164. }
  165.  
  166. // Since index zero is a placeholder for the invalid virtual key or scan code, add one to each MAX value
  167. // to compute the number of elements actually needed to accomodate 0 up to and including VK_MAX or SC_MAX:
  168. #define VK_ARRAY_COUNT (VK_MAX + 1)
  169. #define SC_ARRAY_COUNT (SC_MAX + 1)
  170.  
  171. #define INPUT_BUFFER_SIZE 16384
  172.  
  173. enum InputStatusType {INPUT_OFF, INPUT_IN_PROGRESS, INPUT_TIMED_OUT, INPUT_TERMINATED_BY_MATCH
  174.     , INPUT_TERMINATED_BY_ENDKEY, INPUT_LIMIT_REACHED};
  175.  
  176. // Bitwise flags for the end-key arrays:
  177. #define END_KEY_ENABLED 0x01
  178. #define END_KEY_WITH_SHIFT 0x02
  179. #define END_KEY_WITHOUT_SHIFT 0x04
  180.  
  181. struct input_type
  182. {
  183.     InputStatusType status;
  184.     UCHAR *EndVK; // A sparse array that indicates which VKs terminate the input.
  185.     UCHAR *EndSC; // A sparse array that indicates which SCs terminate the input.
  186.     vk_type EndingVK; // The hook puts the terminating key into one of these if that's how it was terminated.
  187.     sc_type EndingSC;
  188.     bool EndedBySC;  // Whether the Ending key was one handled by VK or SC.
  189.     bool EndingRequiredShift;  // Whether the key that terminated the input was one that needed the SHIFT key.
  190.     char **match; // Array of strings, each string is a match-phrase which if entered, terminates the input.
  191.     UINT MatchCount; // The number of strings currently in the array.
  192.     UINT MatchCountMax; // The maximum number of strings that the match array can contain.
  193.     #define INPUT_ARRAY_BLOCK_SIZE 1024  // The increment by which the above array expands.
  194.     char *MatchBuf; // The is the buffer whose contents are pointed to by the match array.
  195.     UINT MatchBufSize; // The capacity of the above above buffer.
  196.     bool BackspaceIsUndo;
  197.     bool CaseSensitive;
  198.     bool IgnoreAHKInput; // Whether input from any AHK script is ignored for the purpose of finding a match.
  199.     bool TranscribeModifiedKeys; // Whether the input command will attempt to transcribe modified keys such as ^c.
  200.     bool Visible;
  201.     bool FindAnywhere;
  202.     char *buffer; // Stores the user's actual input.
  203.     int BufferLength; // The current length of what the user entered.
  204.     int BufferLengthMax; // The maximum allowed length of the input.
  205.     input_type::input_type() // A simple constructor to initialize the fields that need it.
  206.         : status(INPUT_OFF), match(NULL), MatchBuf(NULL), MatchBufSize(0), buffer(NULL)
  207.     {}
  208. };
  209.  
  210.  
  211. //-------------------------------------------
  212.  
  213. struct KeyHistoryItem
  214. {
  215.     vk_type vk;
  216.     sc_type sc;
  217.     char event_type; // space=none, i=ignored, s=suppressed, h=hotkey, etc.
  218.     bool key_up;
  219.     float elapsed_time;  // Time since prior key or mouse button, in seconds.
  220.     // It seems better to store the foreground window's title rather than its HWND since keystrokes
  221.     // might result in a window closing (being destroyed), in which case the displayed key history
  222.     // would not be able to display the title at the time the history is displayed, which would
  223.     // be undesirable.
  224.     // To save mem, could point this into a shared buffer instead, but if that buffer were to run
  225.     // out of space (perhaps due to the target window changing frequently), window logging would
  226.     // no longer be possible without adding complexity to the logging function.  Seems best
  227.     // to keep it simple:
  228. #define KEY_HISTORY_WINDOW_TITLE_SIZE 100
  229.     char target_window[KEY_HISTORY_WINDOW_TITLE_SIZE];
  230. };
  231.  
  232.  
  233. //-------------------------------------------
  234.  
  235.  
  236. LRESULT CALLBACK LowLevelKeybdProc(int aCode, WPARAM wParam, LPARAM lParam);
  237. LRESULT CALLBACK LowLevelMouseProc(int aCode, WPARAM wParam, LPARAM lParam);
  238. LRESULT LowLevelCommon(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, const vk_type aVK
  239.     , sc_type aSC, bool aKeyUp, ULONG_PTR aExtraInfo, DWORD aEventFlags);
  240.  
  241. #define HOTSTRING_INDEX_INVALID INT_MAX  // Use a signed maximum rather than unsigned, in case indexes ever become signed.
  242. #define SuppressThisKey SuppressThisKeyFunc(aHook, lParam, aVK, aSC, aKeyUp, pKeyHistoryCurr, hotkey_id_to_post)
  243. LRESULT SuppressThisKeyFunc(const HHOOK aHook, LPARAM lParam, const vk_type aVK, const sc_type aSC
  244.     , bool aKeyUp, KeyHistoryItem *pKeyHistoryCurr, HotkeyIDType aHotkeyIDToPost
  245.     , WPARAM aHSwParamToPost = HOTSTRING_INDEX_INVALID, LPARAM aHSlParamToPost = 0);
  246.  
  247. #define AllowKeyToGoToSystem AllowIt(aHook, aCode, wParam, lParam, aVK, aSC, aKeyUp, pKeyHistoryCurr, hotkey_id_to_post, false)
  248. #define AllowKeyToGoToSystemButDisguiseWinAlt AllowIt(aHook, aCode, wParam, lParam, aVK, aSC, aKeyUp, pKeyHistoryCurr, hotkey_id_to_post, true)
  249. LRESULT AllowIt(const HHOOK aHook, int aCode, WPARAM wParam, LPARAM lParam, const vk_type aVK, const sc_type aSC
  250.     , bool aKeyUp, KeyHistoryItem *pKeyHistoryCurr, HotkeyIDType aHotkeyIDToPost, bool aDisguiseWinAlt);
  251.  
  252. bool CollectInput(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsIgnored
  253.     , WPARAM &aHotstringWparamToPost, LPARAM &aHotstringLparamToPost);
  254. void UpdateKeybdState(KBDLLHOOKSTRUCT &aEvent, const vk_type aVK, const sc_type aSC, bool aKeyUp, bool aIsSuppressed);
  255. bool KeybdEventIsPhysical(DWORD aEventFlags, const vk_type aVK, bool aKeyUp);
  256. bool DualStateNumpadKeyIsDown();
  257. bool IsDualStateNumpadKey(const vk_type aVK, const sc_type aSC);
  258.  
  259. void ChangeHookState(Hotkey *aHK[], int aHK_count, HookType aWhichHook, HookType aWhichHookAlways);
  260. void AddRemoveHooks(HookType aHooksToBeActive, bool aChangeIsTemporary = false);
  261. bool SystemHasAnotherKeybdHook();
  262. bool SystemHasAnotherMouseHook();
  263. DWORD WINAPI HookThreadProc(LPVOID aUnused);
  264.  
  265. void ResetHook(bool aAllModifiersUp = false, HookType aWhichHook = (HOOK_KEYBD | HOOK_MOUSE)
  266.     , bool aResetKVKandKSC = false);
  267. HookType GetActiveHooks();
  268. void FreeHookMem();
  269. void ResetKeyTypeState(key_type &key);
  270. void GetHookStatus(char *aBuf, int aBufSize);
  271.  
  272. #endif
  273.